/**
 * 
 */
package com.dfhc.pub.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.http.HttpServletRequest;

import org.quickbundle.tools.support.log.RmLogHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.dfhc.ISystemConstant;
import com.dfhc.pub.FileLockException;
import com.dfhc.pub.single.FileLockMap;
import com.dfhc.util.FileOperateHelper;
import com.dfhc.util.StringHelper;

/**
 * 文件锁服务
 * @author longsebo
 */
@Service
public class FileLockService {
	private String path;
	@Autowired
	PubParamService pubParamService;
	/**
	 * 构造重复提交异常
	 * @param id 唯一标识
	 */
	private void throwRepeatException(String id) {
		RmLogHelper.getLogger(this.getClass()).error("请勿重复操作!标识为:"+id);
		throw new FileLockException("请勿重复操作!");
	}
	/**
	 * 通过文件解锁
	 * @param jsguid
	 */
	public void unLockByFile(String jsguid) {
		// 删除锁文件
		long waittime = ISystemConstant.THREAD_WAIT_SLEEP_TIME;
		String lockFileName;
		lockFileName = path+jsguid;
		while (FileOperateHelper.isExists(lockFileName)) {
			try {
				FileOperateHelper.delFile(lockFileName);
				break;
			} catch (Exception e) {
				RmLogHelper.getLogger(getClass()).error("Retry delFile,id:" + jsguid);
				try {
					if (waittime > 2000) {
						waittime = ISystemConstant.THREAD_WAIT_SLEEP_TIME;
					} else {
						waittime = waittime + 1;
					}
					Thread.sleep(waittime);
				} catch (InterruptedException e1) {
					RmLogHelper.getLogger(getClass()).error("文件解锁失败!原因为:"+e1.getMessage());
					throw new FileLockException("文件解锁失败!原因为:"+e1.getMessage());
				}
			}
		}
	}
	/**
	 * 通过文件加锁，如果加锁失败，则等待指定时间,超时抛出异常
	 * @param jsguid 并发控制唯一标示
	 * @param waitForTime 等待时间(秒为单位 )
	 */
	public void lockByFileAndWait(String jsguid,long waitForTime) {
		//获取路径参数
		path = pubParamService.getFileLockPath();
		//目录不存在，则创建
		if(!FileOperateHelper.isExists(path)){
			try {
				FileOperateHelper.newFolder(path);
			} catch (Exception e) {
				String msg = "创建判重目录:"+path+"失败!原因为:"+e.getMessage();
				RmLogHelper.getLogger(this.getClass()).error(msg);
				throw new FileLockException(msg);
			}
		}
		
		// 获取UUID
		String uuid = StringHelper.getUUID();
		String cmpuuid;
		String lockFileName;
		lockFileName = path+jsguid;
		long startTime = System.currentTimeMillis();
		long endTime = System.currentTimeMillis();
		File lockFile = new File(lockFileName);
		try {
			while(true){
				//文件已经存在，则抛出异常
				if (FileOperateHelper.isExists(lockFileName)) {
					//判断是否超时
					if(endTime-startTime>waitForTime*1000){
						throw new FileLockException("等待超时!");
					}
					//睡眠10毫秒
					Thread.sleep(10);
					endTime = System.currentTimeMillis();
				}else{
					FileOperateHelper.newFile(lockFileName, uuid);
					// 重新读入比较,如果相同则认为获取锁成功，否则抛出异常
					cmpuuid = FileOperateHelper.readFileToString(lockFile,
							ISystemConstant.ENCODE_UTF_8);
					cmpuuid = StringHelper.trimCrlf(cmpuuid);
					if (uuid.equals(cmpuuid)) {
						return;
					} else {
						//判断是否超时
						if(endTime-startTime>waitForTime*1000){
							throw new FileLockException("等待超时!");
						}
						//睡眠10毫秒
						Thread.sleep(10);
						endTime = System.currentTimeMillis();
					}
				}
			}
						
		} catch (Exception e) {
			RmLogHelper.getLogger(this.getClass()).error(e.getMessage());
			throw new FileLockException("文件加锁失败!原因为:"+e.getMessage());
		}
	}
	/**
	 * 通过文件流加锁
	 * @param jsguid 并发控制唯一标示
	 */
	public InputStream lockByFileStream(String jsguid) {
		//如果jsguid为空，则返回null
		if(StringHelper.isEmpty(jsguid)){
			return null;
		}
		//获取路径参数
		path = pubParamService.getFileLockPath();
		//目录不存在，则创建
		if(!FileOperateHelper.isExists(path)){
			try {
				FileOperateHelper.newFolder(path);
			} catch (Exception e) {
				String msg = "创建判重目录:"+path+"失败!原因为:"+e.getMessage();
				RmLogHelper.getLogger(this.getClass()).error(msg);
				throw new FileLockException(msg);
			}
		}
		
		// 获取UUID
		String uuid = StringHelper.getUUID();
		String cmpuuid;
		String lockFileName;
		lockFileName = path+jsguid;
		//尝试删除文件，删除失败，就说明在用
		try{
			if(FileOperateHelper.isExists(lockFileName)){
				FileOperateHelper.delFile(lockFileName);
			}
		}catch(Exception e){
			throwRepeatException(jsguid);
		}
		File lockFile = new File(lockFileName);
		try {
			//文件已经存在，则抛出异常
			if (FileOperateHelper.isExists(lockFileName)) {
				throwRepeatException(jsguid);
			} else {
				FileOperateHelper.newFile(lockFileName, uuid);
				// 重新读入比较,如果相同则认为获取锁成功，否则抛出异常
				cmpuuid = FileOperateHelper.readFileToString(lockFile,
						ISystemConstant.ENCODE_UTF_8);
				cmpuuid = StringHelper.trimCrlf(cmpuuid);
				if (uuid.equals(cmpuuid)) {
					FileInputStream in = new FileInputStream(lockFile);
					return in;
				} else {
					throwRepeatException(jsguid);
				}
			}			
		} catch (Exception e) {
			RmLogHelper.getLogger(this.getClass()).error(e.getMessage());
			throw new FileLockException("文件加锁失败!原因为:"+e.getMessage());
		}
		return null;
	}
	/**
	 * 通过文件流解锁
	 * @param jsguid
	 */
	public void unLockByFileStream(String jsguid,InputStream in) {
		//jsguid为空返回
		if(StringHelper.isEmpty(jsguid)){
			return;
		}
		//关闭文件流
		if(in!=null){
			try {
				in.close();
			} catch (IOException e) {
				RmLogHelper.getLogger(getClass()).error("文件解锁失败!原因为:"+e.getMessage());
				throw new  FileLockException("文件解锁失败!原因为:"+e.getMessage());
			}
		}else{
			//文件流对象为空，直接返回
			return;
		}
		// 删除锁文件
		long waittime = ISystemConstant.THREAD_WAIT_SLEEP_TIME;
		String lockFileName;
		lockFileName = path+jsguid;
		while (FileOperateHelper.isExists(lockFileName)) {
			try {
				FileOperateHelper.delFile(lockFileName);
				break;
			} catch (Exception e) {
				RmLogHelper.getLogger(getClass()).error("Retry delFile,id:" + jsguid);
				try {
					if (waittime > 2000) {
						waittime = ISystemConstant.THREAD_WAIT_SLEEP_TIME;
					} else {
						waittime = waittime + 1;
					}
					Thread.sleep(waittime);
				} catch (InterruptedException e1) {
					RmLogHelper.getLogger(getClass()).error("文件解锁失败!原因为:"+e1.getMessage());
					throw new FileLockException("文件解锁失败!原因为:"+e1.getMessage());
				}
			}
		}
	}
	/**
	 * 直接通过jsguid解锁
	 * @param request
	 */
	public void unLockByJsGuid(HttpServletRequest request) {
		//如果存在jsguid参数，则调用文件解锁
    	String jsguid = request.getParameter(ISystemConstant.JSGUID);
    	if(!StringHelper.isEmpty(jsguid)){
    		InputStream instream = FileLockMap.getSingleton().remove(jsguid);
    		if(instream!=null){
    		 unLockByFileStream(jsguid, instream);
    		}
    	}		
	}
}
